package cn.bigfire.wzdj.pojo.bo;

import cn.bigfire.wzdj.util.ByteUtil;
import cn.bigfire.wzdj.util.IdMaps;
import cn.bigfire.wzdj.util.JProtobufUtil;
import cn.bigfire.wzdj.util.ProtostuffUtil;
import cn.bigfire.wzdj.util.protode.DataBuffer;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.TreeMap;

@Slf4j
public class WZDJPack <WZDJBody>{

    WZDJHeader header;
    byte[] bodyLenBytes;
    WZDJBody body;

    public WZDJPack(WZDJHeader header, WZDJBody body) {
        this.header = header;
        this.body = body;
    }

    public byte[] getBytes() {
        if (body == null) {
            return header.getHeaderBytes();
        }
        //否则全量数据
        byte[] headerBytes = header.getHeaderBytes();
        byte[] tmpBytes = body instanceof DataBuffer ? ((DataBuffer) body).getBuffer() : JProtobufUtil.serializer(body);
        byte[] bodyBytes = tmpBytes;
        byte[] lenBytes = cn.hutool.core.util.ByteUtil.intToBytes(bodyBytes.length);
        byte[] data = new byte[headerBytes.length + lenBytes.length + bodyBytes.length];
        System.arraycopy(headerBytes, 0, data, 0, headerBytes.length);
        System.arraycopy(lenBytes, 0, data, headerBytes.length, lenBytes.length);
        System.arraycopy(bodyBytes, 0, data, headerBytes.length + lenBytes.length, bodyBytes.length);
        return data;
    }
    public byte[] getHeaderBytes() {
        return header.getHeaderBytes();
    }

    public byte[] getBodyLenBytes() {
        return bodyLenBytes;
    }

    public void setBodyLenBytes(byte[] bodyLenBytes) {
        this.bodyLenBytes = bodyLenBytes;
    }

    public byte[] getBodyBytes() {
        if (body != null) {
            return ProtostuffUtil.serializer(body);
        } else {
            return new byte[0];
        }
    }

    public static WZDJPack build(WZDJHeader wzdjHeader,byte[] bodyLenBytes, byte[] bodyBytes) {
        WZDJPack wzdjPack = build(wzdjHeader, bodyBytes);
        wzdjPack.setBodyLenBytes(bodyLenBytes);
        return wzdjPack;
    }

    public static WZDJPack build(WZDJHeader wzdjHeader, byte[] bodyBytes) {
        String name = IdMaps.getTypeById(wzdjHeader.getId());
        if (StrUtil.isBlank(name)) {
            System.err.printf("%s[%s,%s] 没在IdMaps中找到,放弃处理%n",
                    DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS"), wzdjHeader.getId(), wzdjHeader.getName());
            return new WZDJPack(wzdjHeader, null);
        }
        //尝试转换对象
        try {
            Class<?> aClass = Class.forName("cn.bigfire.wzdj.pojo.srcVo.Wzdj$" + name);
            Object deserializer = JProtobufUtil.deserializer(bodyBytes, aClass);
            return new WZDJPack(wzdjHeader, deserializer);
        } catch (Throwable e) {
            System.err.printf("[%s,%s] 反序列化失败,打算toTreeMap解数据 size:%s,%n",
                    wzdjHeader.getId(), wzdjHeader.getName(), bodyBytes.length);
        }
        //尝试转换map
        try {
            DataBuffer dataBuffer = DataBuffer.of(bodyBytes);
            TreeMap<String, Object> map = dataBuffer.toMap();
            log.info("新协议:" + JSON.toJSONString(map));
            return new WZDJPack(wzdjHeader, dataBuffer);
        } catch (Throwable e) {
            e.printStackTrace();
            System.err.printf("[%s,%s] ,toTreeMap失败,放弃处理,size:[%s]%n",
                    wzdjHeader.getId(), wzdjHeader.getName(), bodyBytes.length);
        }
        return new WZDJPack(wzdjHeader, null);
    }

    //get set
    public WZDJHeader getHeader() {
        return header;
    }

    public void setHeader(WZDJHeader header) {
        this.header = header;
    }

    public WZDJBody getBody() {
        return body;
    }

    public void setBody(WZDJBody body) {
        this.body = body;
    }

    @Override
    public String toString() {
        if (header.getHeart() == 1) {//心跳不打印
            long headerTime = header.getTime() * 1000L;
            String headerTimeStr = DateUtil.formatDateTime(new Date(headerTime));
            return String.format("心跳:%s,%s", headerTime, headerTimeStr);
        } else {
            String size = ByteUtil.getSize(getBytes().length);
            String bodyStr = "";
            if (body instanceof DataBuffer) {
                DataBuffer dataBuffer = (DataBuffer) body;
                TreeMap<String, Object> map = dataBuffer.toMap();
                bodyStr = JSON.toJSONString(map);
            } else {
                bodyStr = JSON.toJSONString(body);
            }
            return String.format("[%s,%s,%s,%s]:%s", header.getId(), header.getName(),
                    header.getZhName(), size, bodyStr);
        }
    }

}
